/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package vn.support.ui.frame;

import static vn.support.system.SystemProperties.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.ResourceBundle;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.Timer;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.net.URLCodec;
import org.apache.commons.lang.StringEscapeUtils;
import vn.support.connection.Connection;
import vn.support.connection.RequestConnection;
import vn.support.connection.factory.DataObjectFactory;
import vn.support.connection.factory.EntityFactory;
import vn.support.connection.response.processor.ResponseProcessor;
import vn.support.connection.response.processor.impl.StaffChatProcessor;
import vn.support.core.dto.ChatInfo;
import vn.support.core.dto.ChatMessage;
import vn.support.core.dto.ChatResponse;
import vn.support.core.dto.DataObject;
import vn.support.core.dto.SessionData;
import vn.support.system.SystemProperties;
import vn.support.ui.ChatView;

/**
 *
 * @author nttuyen
 */
public abstract class AbstractChatView extends JFrame implements ChatView{
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	protected final ChatInfo chatInfo;
    protected final SessionData session;
    protected final Connection connection;
    protected ResourceBundle bundle;

    protected final DataObject dataChatLoop;
    protected final Timer chatLoopTimer;
    protected final Timer endChatTimer;

    protected final EntityFactory factory;

    public AbstractChatView(ChatInfo chatInfo) {
        super.setIconImage(new ImageIcon(getClass().getResource(SystemProperties.getValue("support.chat.system.icon"))).getImage());
        this.session = SystemProperties.get(SESSION);
        this.chatInfo = chatInfo;
        this.connection = new RequestConnection();
        this.bundle = ResourceBundle.getBundle(UI_BUNDLE);
        
        this.dataChatLoop = getDataChatLoop();
        this.chatLoopTimer = getChatLoopTimer();
        this.endChatTimer = getEndChatTimer();

        this.factory = new DataObjectFactory();

        chatLoopTimer.start();
        SystemProperties.addView(this);
    }

    @Override
    public void endChat() {
        this.chatLoopTimer.stop();
        SystemProperties.getData().remove(ChatView.class.getName() + "#" + chatInfo.getChatSessionId());
        SystemProperties.getData().remove(ChatView.class.getName() + "#" + chatInfo.getVisitorSessionId());
        
        DataObject endChat = new DataObject(Connection.END_CHAT_ACTION);
        endChat.set("sessionid", session.getSessionId());
        endChat.set("chatsessionid", this.chatInfo.getChatSessionId());
        endChat.set(Connection.RESPONSE_PROCESSOR, new StaffChatProcessor());
        this.connection.execute(endChat);
    }

    public void send(final String message) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    String content = bundle("ui.chat.chatcontent.send.tagopen") + chatInfo.getStaffName() + ":" + bundle("ui.chat.chatcontent.send.tagclose");
                    content += " " + SystemProperties.emotionMessage(message);
                    addMessage(content);

                    URLCodec urlColdec = new URLCodec();
                    DataObject sendData = new DataObject(Connection.POST_CHAT_MESSAGE_ACTION);
                    sendData.set("sessionid", session.getSessionId());
                    sendData.set("chatsessionid", chatInfo.getChatSessionId());
                    sendData.set("base64", "true");
                    sendData.set("message", urlColdec.encode(new String(Base64.encodeBase64(StringEscapeUtils.escapeHtml(message).getBytes("UTF-8")))));
                    sendData.set(Connection.RESPONSE_PROCESSOR, new StaffChatProcessor());
                    connection.execute(sendData);
                    } catch (Exception ex) {}
            }
        }).start();
    }

    protected String bundle(String key) {
        if(this.bundle.containsKey(key)) {
            return this.bundle.getString(key);
        }
        return key;
    }
    protected void chatLoop() {
        this.connection.execute(this.dataChatLoop);
    }
    
    @Override
    public void setVisible(boolean b) {
        if(this.endChatTimer.isRunning()) {
            this.endChatTimer.stop();
        }
        super.setVisible(b);
    }

    @Override
    public void dispose() {
        this.endChat();
        SystemProperties.removeView(this);
        super.dispose();
    }
    
    protected final DataObject getDataChatLoop() {
        DataObject data = new DataObject(Connection.CHAT_LOOP_XML_ACTION);
        data.set("sessionid", chatInfo.getSessionId());
        data.set("chatsessionid", chatInfo.getChatSessionId());
        data.set("chatchildid", chatInfo.getChatChildId());
        data.set(Connection.RESPONSE_PROCESSOR, new ResponseProcessor() {
            @Override
            public DataObject process(DataObject data) {
                String xml = data.get(Connection.DTO_RESPONSE_DATA);
                if(!xml.startsWith("<?xml")) {
                    if(Connection.RESPONSE_SESSION_TIMEOUT.equals(xml)){
                        addMessage(bundle("ui.chat.notice.session.timeout"));
                        chatLoopTimer.stop();
                        endChatTimer.setInitialDelay(60000);
                        endChatTimer.start();
                    }
                    return data;
                }
                Collection<ChatResponse> chatResponses = factory.create(xml, "//swiftwinapp", ChatResponse.class);
                for(ChatResponse response: chatResponses) {
                    if(response.getNoloop() == 1) {
                        String content = bundle("ui.chat.chatcontent.end.tagopen");
                        content += bundle("ui.chat.chatcontent.end.message");
                        content += bundle("ui.chat.chatcontent.end.tagclose");
                        addMessage(content);
                        chatLoopTimer.stop();
                    }
                    if(response.getMessages() != null) {
                        StringBuilder typingNotify = new StringBuilder();
                        for(ChatMessage msg : response.getMessages()) {
                            if(msg.getType().equals("message")) {
                                if(!isVisible()) setVisible(true);
                                if(endChatTimer.isRunning()) {
                                    endChatTimer.stop();
                                }
                                
                                String content = bundle("ui.chat.chatcontent.receive.tagopen") + msg.getFrom() + ": " + bundle("ui.chat.chatcontent.receive.tagclose");
                                content += SystemProperties.emotionMessage(StringEscapeUtils.unescapeHtml(new String(Base64.decodeBase64(msg.getContent().getBytes()))));
                                addMessage(content);
                            } else if(msg.getType().equals("clientnoresponse") || msg.getType().equals("chatexpired")) {
                                String content = bundle("ui.chat.chatcontent.notice.tagopen");
                                content += msg.getContent();
                                content += bundle("ui.chat.chatcontent.notice.tagclose");
                                addMessage(content);
                                
                            } else if(msg.getType().equals("leave")) {
                                String content = bundle("ui.chat.chatcontent.leave.tagopen");
                                content += msg.getContent();
                                content += " " + bundle("ui.chat.chatcontent.leave.message");
                                content += bundle("ui.chat.chatcontent.leave.tagclose");
                                addMessage(content);
                                
                            } else if(msg.getType().equals("enter")) {
                                String content = bundle("ui.chat.chatcontent.enter.tagopen");
                                content += msg.getContent();
                                content += " " + bundle("ui.chat.chatcontent.enter.message");
                                content += bundle("ui.chat.chatcontent.enter.tagclose");
                                addMessage(content);
                                
                            } else if(msg.getType().equals("chatend")) {
                                String content = bundle("ui.chat.chatcontent.end.tagopen");
                                content += bundle("ui.chat.chatcontent.end.message");
                                content += bundle("ui.chat.chatcontent.end.tagclose");
                                addMessage(content);
                                chatLoopTimer.stop();
                            } else if(msg.getType().equals("typing")) {
                                typingNotify.append(msg.getContent()).append(", ");
                            }
                            flashFrame();
                        }
                        if(typingNotify.length() > 0) {
                            int index = typingNotify.lastIndexOf(", ");
                            typingNotify.replace(index, typingNotify.length(), "");
                            typingNotify.append(" ").append(SystemProperties.getValue("ui.chat.chatcontent.typing"));
                            chatNotify(typingNotify.toString());
                        } else {
                            chatNotify("");
                        }
                    } else {
                        chatNotify("");
                    }
                }
                return data;
            }
        });
        return data;
    }
    
    protected final void flashFrame() {
        this.toFront();
    }

    protected final Timer getChatLoopTimer() {
        Timer timer = new Timer(TIME_LOOP, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                chatLoop();
            }
        });
        timer.setRepeats(true);
        return timer;
    }
    
    protected final Timer getEndChatTimer() {
        Timer timer = new Timer(TIME_TO_END, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                endChat();
            }
        });
        timer.setRepeats(false);
        return timer;
    }
}
